package com.yoj.questionservice.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yoj.model.dto.question.QuestionAddRequest;
import com.yoj.model.dto.question.QuestionQueryRequest;
import com.yoj.model.dto.question.QuestionUpdateRequest;
import com.yoj.common.utils.RedisLimiterManager;
import com.yoj.questionservice.service.QuestionService;
import com.yoj.questionservice.service.QuestionSubmitService;
import com.yoj.common.annotaion.AuthCheck;
import com.yoj.common.common.BaseResponse;
import com.yoj.common.common.DeleteRequest;
import com.yoj.common.common.ResultCodeEnum;
import com.yoj.common.constant.RedisKeyConstant;
import com.yoj.common.constant.UserConstant;
import com.yoj.common.exception.BusinessException;
import com.yoj.model.dto.questionsubmit.QuestionSubmitAddRequest;
import com.yoj.model.dto.questionsubmit.QuestionSubmitQueryRequest;
import com.yoj.model.entity.Question;
import com.yoj.model.entity.User;
import com.yoj.model.enums.QuestionSubmitLanguageEnum;
import com.yoj.model.vo.QuestionSubmitVO;
import com.yoj.model.vo.QuestionVO;
import com.yoj.serviceclient.service.user.UserFeignClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * 题目接口
 */
@RestController
@RequestMapping("/")
@Slf4j
@Api(tags = "题目服务接口")
public class QuestionController {

    @Resource
    private QuestionService questionService;

    @Resource
    private UserFeignClient userFeignClient;

    @Resource
    private QuestionSubmitService questionSubmitService;

    @Resource
    private RedisLimiterManager redisLimiterManager;

    // region 增删改查

    /**
     * 创建题目
     * @param questionAddRequest 题目创建请求参数
     * @param request            HTTP 请求对象
     * @return BaseResponse 对象，包含新创建题目的 ID
     */
    @PostMapping("/add")
    @ApiOperation(value = "创建题目")
    public BaseResponse<Long> addQuestion(@RequestBody QuestionAddRequest questionAddRequest, HttpServletRequest request) {
        if (questionAddRequest == null) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        Long addQuestionId = questionService.addQuestion(questionAddRequest, request);
        return BaseResponse.success(addQuestionId);
    }

    /**
     * 删除题目
     * @param deleteRequest 题目删除请求参数
     * @param request       HTTP 请求对象
     * @return BaseResponse 对象，包含题目是否删除成功
     */
    @PostMapping("/delete")
    @ApiOperation(value = "删除题目")
    public BaseResponse<Boolean> deleteQuestion(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        Boolean deleteQuestion = questionService.deleteQuestion(deleteRequest, request);
        return BaseResponse.success(deleteQuestion);
    }

    /**
     * 更新题目（仅管理员）
     * @param questionUpdateRequest 题目更新请求参数
     * @return BaseResponse 对象，包含是否更新成功
     */
    @PostMapping("/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @ApiOperation(value = "更新题目（仅管理员）")
    public BaseResponse<Boolean> updateQuestion(@RequestBody QuestionUpdateRequest questionUpdateRequest) {
        if (questionUpdateRequest == null || questionUpdateRequest.getId() <= 0) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        Boolean updateQuestion = questionService.updateQuestion(questionUpdateRequest);
        return BaseResponse.success(updateQuestion);
    }

    /**
     * 根据题目 id 获取题目
     * @param questionId 题目 id
     * @return BaseResponse 对象，包含题目信息
     */
    @GetMapping("/get")
    @ApiOperation(value = "根据题目 id 获取题目")
    public BaseResponse<Question> getQuestionById(@RequestParam("id") long questionId, HttpServletRequest request) {
        if (questionId <= 0) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        Question question = questionService.getQuestionById(questionId, request);
        return BaseResponse.success(question);
    }

    /**
     * 根据 id 获取题目视图
     * @param questionId 题目 id
     * @return BaseResponse 对象，包含脱敏后的题目信息
     */
    @GetMapping("/get/vo")
    @ApiOperation(value = "根据 id 获取脱敏后的题目信息")
    public BaseResponse<QuestionVO> getQuestionVOById(@RequestParam("id") long questionId, HttpServletRequest request) {
        if (questionId <= 0) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        QuestionVO questionVO = questionService.getQuestionVOById(questionId, request);
        return BaseResponse.success(questionVO);
    }

    /**
     * 题目管理：分页获取题目列表（仅管理员）
     * @param questionQueryRequest 题目查询请求信息
     * @return BaseResponse 对象，包含题目分页信息
     */
    @PostMapping("/list/page")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    @ApiOperation(value = "分页获取题目列表（仅管理员）")
    public BaseResponse<Page<Question>> listQuestionByPage(@RequestBody QuestionQueryRequest questionQueryRequest) {
        if (questionQueryRequest == null) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        // 分页查询题目信息
        Page<Question> questionPage = questionService.getQuestionPage(questionQueryRequest);
        return BaseResponse.success(questionPage);
    }

    /**
     * 分页获取题目视图列表（封装类）
     * @param questionQueryRequest 题目查询请求参数
     * @param request              HTTP 请求对象
     * @return BaseResponse 对象，包含题目分页信息
     */
    @PostMapping("/list/page/vo")
    @ApiOperation(value = "分页获取题目视图列表")
    public BaseResponse<Page<QuestionVO>> getQuestionVOList(@RequestBody QuestionQueryRequest questionQueryRequest,
                                                            HttpServletRequest request) {
        if (questionQueryRequest == null) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        // 分页查询题目列表
        Page<QuestionVO> questionVOPage = questionService.getQuestionVOPage(questionQueryRequest, request);
        return BaseResponse.success(questionVOPage);
    }

    /**
     * 分页获取当前用户创建的题目列表
     * @param questionQueryRequest 题目查询请求参数
     * @param request              HTTP 请求对象
     * @return BaseResponse 对象，包含题目分页信息
     */
    @PostMapping("/my/list/page/vo")
    @ApiOperation(value = "分页获取当前用户创建的题目列表")
    public BaseResponse<Page<QuestionVO>> listMyQuestionVOByPage(@RequestBody QuestionQueryRequest questionQueryRequest,
                                                                 HttpServletRequest request) {
        if (questionQueryRequest == null) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        Page<QuestionVO> userQuestionVOPage = questionService.getUserQuestionVOPage(questionQueryRequest, request);
        return BaseResponse.success(userQuestionVOPage);
    }

    // endregion

    /**
     * 获取编程语言
     * @return BaseResponse 对象，包含编程语言列表
     */
    @GetMapping("/get/language")
    @ApiOperation(value = "获取编程语言")
    public BaseResponse<List<String>> getCodeLanguage() {
        return BaseResponse.success(QuestionSubmitLanguageEnum.getValues());
    }

    /**
     * 提交题目
     * @param questionSubmitAddRequest 题目查询请求信息
     * @param request                  HTTP 请求对象
     * @return BaseResponse 对象，包含题目提交 id
     */
    @PostMapping("/question_submit/do")
    @ApiOperation("提交题目")
    public BaseResponse<Long> submitQuestion(@RequestBody QuestionSubmitAddRequest questionSubmitAddRequest,
                                             HttpServletRequest request) {
        // 判断请求参数、提交题目id不能为空
        if (questionSubmitAddRequest == null || questionSubmitAddRequest.getQuestionId() <= 0) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        // 判断用户是否登录
        final User loginUser = userFeignClient.getLoginUser(request);
        // 限流：每5秒只能提交1次题目
        boolean isAllowed = redisLimiterManager.isAllowed(RedisKeyConstant.LIMIT_KEY_PREFIX + loginUser.getId().toString(), 1, 5);
        // 判断是否超过限流的次数
        if (!isAllowed) {
            log.error("用户：{} 提交题目：{} 过于频繁", loginUser.getId(), questionSubmitAddRequest.getQuestionId());
            return BaseResponse.error(ResultCodeEnum.TOO_MANY_REQUEST, "提交过于频繁，请稍后重试");
        }
        Long submitQuestionId = questionService.submitQuestion(questionSubmitAddRequest, request);
        return BaseResponse.success(submitQuestionId);
    }

    // question_submit

    /**
     * 分页获取题目提交表（除了管理员外，普通用户只能看到非答案的提交代码等公开信息）
     * @param questionSubmitQueryRequest 题目提交查询参数
     * @return BaseResponse 对象，包含题目提交分页信息
     */
    @PostMapping("/question_submit/list/page")
    @ApiOperation(value = "分页获取题目提交表")
    public BaseResponse<Page<QuestionSubmitVO>> listQuestionSubmitByPage(@RequestBody QuestionSubmitQueryRequest questionSubmitQueryRequest,
                                                                         HttpServletRequest request) {
        if (questionSubmitQueryRequest == null) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        Page<QuestionSubmitVO> questionSubmitVOPage = questionSubmitService.getQuestionSubmitVOPage(questionSubmitQueryRequest, request);
        return BaseResponse.success(questionSubmitVOPage);
    }

    /**
     * 分页获取用户自己的题目提交信息
     */
    @PostMapping("/question_submit/list/my_submit/page")
    @ApiOperation(value = "用户查询自己的题目提交信息")
    public BaseResponse<Page<QuestionSubmitVO>> listUserQuestionSubmitByPage(@RequestBody QuestionSubmitQueryRequest questionSubmitQueryRequest,
                                                                             HttpServletRequest request) {
        if (questionSubmitQueryRequest == null) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        Page<QuestionSubmitVO> questionSubmitVOPage = questionSubmitService.getUserQuestionSubmitVOPage(questionSubmitQueryRequest, request);
        return BaseResponse.success(questionSubmitVOPage);
    }

    /**
     * 根据题目提交id查询判题结果
     */
    @GetMapping("/question_submit/get/id")
    public BaseResponse<QuestionSubmitVO> getJudgeResult(Long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ResultCodeEnum.PARAMS_ERROR);
        }
        QuestionSubmitVO questionSubmitVO = questionSubmitService.getQuestionSubmitVO(id, request);
        return BaseResponse.success(questionSubmitVO);
    }

}